package com.shlh.saas.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;

/**
 * 性能监控工具类
 * 用于监控方法执行时间和性能统计
 */
@Component
@Slf4j
public class PerformanceMonitor {

    /**
     * 性能统计数据
     */
    private static class PerformanceStats {
        private final AtomicLong totalTime = new AtomicLong(0);
        private final AtomicLong callCount = new AtomicLong(0);
        private final AtomicLong minTime = new AtomicLong(Long.MAX_VALUE);
        private final AtomicLong maxTime = new AtomicLong(0);

        public void addTime(long time) {
            totalTime.addAndGet(time);
            callCount.incrementAndGet();
            
            // 更新最小时间
            long currentMin = minTime.get();
            while (time < currentMin && !minTime.compareAndSet(currentMin, time)) {
                currentMin = minTime.get();
            }
            
            // 更新最大时间
            long currentMax = maxTime.get();
            while (time > currentMax && !maxTime.compareAndSet(currentMax, time)) {
                currentMax = maxTime.get();
            }
        }

        public long getAverageTime() {
            long count = callCount.get();
            return count > 0 ? totalTime.get() / count : 0;
        }

        public long getTotalTime() { return totalTime.get(); }
        public long getCallCount() { return callCount.get(); }
        public long getMinTime() { 
            long min = minTime.get();
            return min == Long.MAX_VALUE ? 0 : min;
        }
        public long getMaxTime() { return maxTime.get(); }
    }

    private final ConcurrentHashMap<String, PerformanceStats> statsMap = new ConcurrentHashMap<>();

    /**
     * 监控方法执行时间
     */
    public <T> T monitor(String methodName, Supplier<T> supplier) {
        long startTime = System.currentTimeMillis();
        try {
            T result = supplier.get();
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            
            recordTime(methodName, executionTime);
            
            if (executionTime > 1000) { // 超过1秒的操作记录警告
                log.warn("方法 {} 执行时间较长: {}ms", methodName, executionTime);
            } else {
                log.debug("方法 {} 执行时间: {}ms", methodName, executionTime);
            }
            
            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            log.error("方法 {} 执行失败，耗时: {}ms", methodName, executionTime, e);
            throw e;
        }
    }

    /**
     * 监控无返回值的方法
     */
    public void monitor(String methodName, Runnable runnable) {
        monitor(methodName, () -> {
            runnable.run();
            return null;
        });
    }

    /**
     * 记录执行时间
     */
    private void recordTime(String methodName, long executionTime) {
        statsMap.computeIfAbsent(methodName, k -> new PerformanceStats())
                .addTime(executionTime);
    }

    /**
     * 获取方法性能统计信息
     */
    public String getMethodStats(String methodName) {
        PerformanceStats stats = statsMap.get(methodName);
        if (stats == null) {
            return String.format("方法 %s 暂无统计数据", methodName);
        }

        return String.format(
            "方法 %s 性能统计 - 调用次数: %d, 总耗时: %dms, 平均耗时: %dms, 最小耗时: %dms, 最大耗时: %dms",
            methodName,
            stats.getCallCount(),
            stats.getTotalTime(),
            stats.getAverageTime(),
            stats.getMinTime(),
            stats.getMaxTime()
        );
    }

    /**
     * 获取所有方法的性能统计报告
     */
    public String getPerformanceReport() {
        if (statsMap.isEmpty()) {
            return "暂无性能统计数据";
        }

        StringBuilder report = new StringBuilder();
        report.append("=== 性能监控报告 ===\n");
        
        statsMap.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue().getTotalTime(), e1.getValue().getTotalTime()))
                .forEach(entry -> {
                    String methodName = entry.getKey();
                    PerformanceStats stats = entry.getValue();
                    
                    report.append(String.format(
                        "%-40s | 调用: %6d次 | 总耗时: %8dms | 平均: %6dms | 最小: %6dms | 最大: %6dms\n",
                        methodName,
                        stats.getCallCount(),
                        stats.getTotalTime(),
                        stats.getAverageTime(),
                        stats.getMinTime(),
                        stats.getMaxTime()
                    ));
                });
        
        return report.toString();
    }

    /**
     * 清除统计数据
     */
    public void clearStats() {
        statsMap.clear();
        log.info("性能统计数据已清除");
    }

    /**
     * 清除指定方法的统计数据
     */
    public void clearMethodStats(String methodName) {
        statsMap.remove(methodName);
        log.info("已清除方法 {} 的性能统计数据", methodName);
    }

    /**
     * 获取性能警告（执行时间超过阈值的方法）
     */
    public String getPerformanceWarnings(long thresholdMs) {
        StringBuilder warnings = new StringBuilder();
        warnings.append("=== 性能警告（执行时间超过 ").append(thresholdMs).append("ms 的方法）===\n");
        
        boolean hasWarnings = false;
        for (Map.Entry<String, PerformanceStats> entry :statsMap.entrySet()) {
            String methodName = entry.getKey();
            PerformanceStats stats = entry.getValue();
            
            if (stats.getAverageTime() > thresholdMs || stats.getMaxTime() > thresholdMs * 2) {
                hasWarnings = true;
                warnings.append(String.format(
                    "⚠️  %-40s | 平均: %6dms | 最大: %6dms | 调用: %6d次\n",
                    methodName,
                    stats.getAverageTime(),
                    stats.getMaxTime(),
                    stats.getCallCount()
                ));
            }
        }
        
        if (!hasWarnings) {
            warnings.append("暂无性能警告\n");
        }
        
        return warnings.toString();
    }

    /**
     * 记录数据库查询性能
     */
    public <T> T monitorDbQuery(String queryName, Supplier<T> querySupplier) {
        return monitor("DB_QUERY_" + queryName, querySupplier);
    }

    /**
     * 记录数据处理性能
     */
    public <T> T monitorDataProcess(String processName, Supplier<T> processSupplier) {
        return monitor("DATA_PROCESS_" + processName, processSupplier);
    }

    /**
     * 记录导出操作性能
     */
    public <T> T monitorExport(String exportName, Supplier<T> exportSupplier) {
        return monitor("EXPORT_" + exportName, exportSupplier);
    }

    /**
     * 简单的时间测量工具
     */
    public static class Timer {
        private final long startTime;
        private final String name;

        public Timer(String name) {
            this.name = name;
            this.startTime = System.currentTimeMillis();
        }

        public long stop() {
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            log.debug("计时器 {} 耗时: {}ms", name, duration);
            return duration;
        }

        public long stopAndLog() {
            long duration = stop();
            log.info("操作 {} 完成，耗时: {}ms", name, duration);
            return duration;
        }
    }

    /**
     * 创建计时器
     */
    public static Timer startTimer(String name) {
        return new Timer(name);
    }
}
